/**
 * Copyright (C) 2010 - 2013 Harry Glasgow
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.jaden.ui.dialog.projectdefinition;

import com.googlecode.jaden.common.config.IOConfiguration;
import com.googlecode.jaden.common.other.Utils;
import com.googlecode.jaden.ui.UiUtils;
import com.googlecode.jaden.ui.dialog.BaseDialog;
import static com.googlecode.jaden.ui.Constants.*;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.prefs.Preferences;

public class EditMapIODialog extends BaseDialog {

    private DefaultListModel listModel;
    private JList list;
    private IOConfiguration configuration;
    private JButton editButton;
    private JButton removeButton;

    public EditMapIODialog(EditProjectDefinitionDialog dialog, IOConfiguration configuration, Preferences preferences) {
        super(dialog, DIALOG_PROJECT_DETAILS_MAP_TITLE);
        this.configuration = configuration;

        listModel = new DefaultListModel();
        list = new JList(listModel);
        list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() >= 2) {
                    editKV();
                }
            }
        });

        JScrollPane scroll = new JScrollPane(list);
        scroll.setPreferredSize(new Dimension(200, 125));
        JPanel mainPanel = UiUtils.verticalList(UiUtils.horizontalList(scroll));
        setMainPanel(mainPanel, preferences);

        JButton addButton = UiUtils.createButton(LABEL_ADD_TEXT);
        editButton = UiUtils.createButton(LABEL_EDIT_TEXT);
        removeButton = UiUtils.createButton(LABEL_REMOVE_TEXT);

        addButton(addButton);
        addButton(editButton);
        addButton(removeButton);

        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                addKV();
            }
        });

        editButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                editKV();
            }
        });

        removeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                removeKV();
            }
        });

        // Order by value, not key, as this is more relevant.
        Map<Double, String> reverserMap = new TreeMap<Double, String>();
        for (Map.Entry<String, Double> entry : configuration.getMap().entrySet()) {
            reverserMap.put(entry.getValue(), entry.getKey());
        }
        for (Map.Entry<Double, String> entry : reverserMap.entrySet()) {
            KVWrapper q = new KVWrapper(entry.getValue(), entry.getKey());
            listModel.addElement(q);
        }

        list.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                enableButtons();
            }
        });

        enableButtons();
    }

    private void enableButtons() {
        editButton.setEnabled(list.getSelectedIndex() >= 0);
        removeButton.setEnabled(list.getSelectedIndex() >= 0);
    }

    private void addKV() {
        AddEditMapIOEntryDialog dialog = new AddEditMapIOEntryDialog(this, "", 0.0, getPreferences());
        dialog.setVisible(true);
    }

    private void editKV() {
        KVWrapper wrapper = (KVWrapper) list.getSelectedValue();
        AddEditMapIOEntryDialog dialog = new AddEditMapIOEntryDialog(this, wrapper.key, wrapper.value, getPreferences());
        dialog.setVisible(true);
    }

    private void removeKV() {
        listModel.removeElementAt(list.getSelectedIndex());
    }

    protected void doOk() {
        if (listModel.getSize() < 2) {
            JOptionPane.showMessageDialog(this, Utils.translate(ERROR_NO_MAPS));
        } else {
            List<Double> values = new ArrayList<Double>();
            for (int i = 0; i < listModel.getSize(); i++) {
                KVWrapper wrapper = (KVWrapper) listModel.getElementAt(i);
                if (values.contains(wrapper.value)) {
                    JOptionPane.showMessageDialog(this, Utils.translate(ERROR_DUPLICATE_VALUES));
                    return;
                } else {
                    values.add(wrapper.value);
                }
            }
            configuration.getMap().clear();
            for (int i = 0; i < listModel.getSize(); i++) {
                KVWrapper wrapper = (KVWrapper) listModel.getElementAt(i);
                configuration.getMap().put(wrapper.key, wrapper.value);
            }
            dispose();
        }
    }

    public void putKV(String k, double v) {
        KVWrapper newWrapper = new KVWrapper(k, v);
        for (int i = 0; i < listModel.getSize(); i++) {
            KVWrapper existingWrapper = (KVWrapper) listModel.getElementAt(i);
            if (newWrapper.equals(existingWrapper)) {
                listModel.removeElementAt(i);
                listModel.insertElementAt(newWrapper, i);
                return;
            }
        }
        listModel.addElement(newWrapper);
    }

    private static class KVWrapper {

        private final String key;
        private final double value;

        KVWrapper(String key, double value) {
            this.key = key;
            this.value = value;
        }

        public String toString() {
            return key + " = " + value;
        }

        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }

            KVWrapper wrapper = (KVWrapper) obj;

            if (!key.equals(wrapper.key)) {
                return false;
            }

            return true;
        }

        public int hashCode() {
            return key.hashCode();
        }
    }
}